module packet_decode(
    input clk , //时钟
    input rst_n , //复位

    input [7:0] uart_rx_data , //UART 接收数据完成信号
    input uart_rx_done , //UART 接收的数据
    input packet_tx_done, //一包数据全部发送完成标志

    output  reg fun0_en, //功能0：启动(无限制)
    output  reg fun1_en, //功能1：停止
    output  reg fun2_en, //功能2：清零计数
    output  reg fun3_en, //功能3：启动计数
    output  reg fun4_en, //功能4: 查询状态
    output  reg   [15:0]   fun_parmeter,     //功能的参数,2个字节16位，这儿是颗粒个数

    output  reg            parse_done    ,   //解包完成标志
    output  reg   [7:0]    parse_result  ,   //解包后的结果,8'h00:解析正确 8'hEx:解析错误
    output  reg   [7:0]    parse_cmd         //命令 8'd0-8'd4对应0-4fun
    );

    //parameter define
    parameter PACKET_HEAD    = 8'h55;      //定义数据包头

    parameter FUN0        = 8'h00;      //功能0：启动(无限制)
    parameter FUN1        = 8'h01;      //功能1：停止
    parameter FUN2        = 8'h02;      //功能2：清零计数
    parameter FUN3        = 8'h03;      //功能3：启动计数
    parameter FUN4        = 8'h04;      //功能4: 查询状态

    parameter ERR_HEAD       = 8'hE0;      //包头检测错误
    parameter ERR_CMD        = 8'hE1;      //发送无效命令报错
    parameter ERR_DATA_LEN   = 8'hE2;      //有效数据长度发送错误
    parameter ERR_CHECKSUM   = 8'hE3;      //校验错误

    parameter PARSE_OK       = 8'h00;      //数据包解析正确

    //localparam define 状态机定义
    localparam  st_head      = 6'b00_0001; //解析包头
    localparam  st_cmd       = 6'b00_0010; //解析命令
    localparam  st_len       = 6'b00_0100; //解析数据有效长度
    localparam  st_data      = 6'b00_1000; //解析数据
    localparam  st_check     = 6'b01_0000; //校验
    localparam  st_rx_end    = 6'b10_0000; //结束状态

    //reg define
    reg    [5:0]    cur_state      ; //状态机的现态
    reg    [5:0]    next_state     ; //状态机的次态

    reg    [2:0]    data_cnt       ; //接收到的数据计数器
    reg    [7:0]    data_len       ; //接收的有效数据长度
    reg    [7:0]    rec_data       ; //接收到的数据
    reg    [7:0]    rec_data_t     ; //接收的数据寄存一拍，这样就是存了16位
    reg    [7:0]    checksum       ; //包的累加校验和
    reg             skip_en        ; //控制状态跳转使能信号

    //同步时序模块
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) 
            cur_state <= st_head;
        else
            cur_state <= next_state;
    end

    //转态转换条件
    always@(*)begin
        next_state = st_head;
        case(cur_state)
            st_head:begin //解析包头
                if(skip_en)
                    next_state = st_cmd;
                else if(parse_result == ERR_HEAD)
                    next_state = st_rx_end;
                else
                    next_state = st_head;
            end
            st_cmd:begin //解析命令
                if(skip_en)
                    next_state = st_len;
                else if(parse_result == ERR_CMD)
                    next_state = st_rx_end;
                else
                    next_state = st_cmd;
            end
            st_len:begin //解析数据长度
                if(skip_en)
                    next_state = st_data;
                else if(parse_result == ERR_DATA_LEN) 
                    next_state = st_rx_end;
                else
                    next_state = st_len;
            end
            st_data:begin //解析数据
                if(skip_en)
                    next_state = st_check;
                else
                    next_state = st_data;
            end
            st_check:begin //校验位对比
                if(skip_en)
                    next_state = st_rx_end;
                else if( parse_result == ERR_CHECKSUM)
                    next_state = st_rx_end;
                else
                    next_state = st_check;
            end
            st_rx_end :begin //接收结束
                if(packet_tx_done) //发送串口完了后input进来的
                    next_state = st_head;
                else
                    next_state = st_rx_end;
            end
            default:
                next_state = st_head;
        endcase
    end

    //时序电路描述状态输出
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            data_cnt     <= 3'b0;
            parse_result <= 8'b0;
            parse_cmd    <= 8'b0;
            data_len     <= 8'b0;
            parse_done   <= 1'b0;
            skip_en      <= 1'b0;
            rec_data     <= 8'b0;
            rec_data_t   <= 8'b0;
            checksum     <= 8'b0;
        end
        else begin
            skip_en <= 1'b0;
            parse_done <= 1'b0;
            case(cur_state)
                st_head: begin  //检测包头-----------------------------
                    if(uart_rx_done)begin
                        if(uart_rx_data == PACKET_HEAD)begin
                            skip_en <= 1'b1;
                            checksum <= PACKET_HEAD;
                        end
                        else begin
                            parse_result <= ERR_HEAD;        //包头检测错误
                            parse_done    <= 1'b1;
                        end
                    end
                end
                st_cmd: begin //解析命令---------------------------------
                    if(uart_rx_done)begin
                        if(uart_rx_data == FUN0 || uart_rx_data == FUN1 || uart_rx_data == FUN2 || uart_rx_data == FUN3 || uart_rx_data == FUN4)begin
                            skip_en <= 1'b1;
                            parse_cmd <= uart_rx_data;
                            checksum <= checksum + uart_rx_data;
                        end
                        else begin
                            parse_result <= ERR_CMD;        //发送无效命令报错,未定义
                            parse_done    <= 1'b1;
                        end
                    end
                end
                st_len: begin //接收有效数据位的个数-----------------------
                    if (uart_rx_done) begin
                        if (uart_rx_data == 8'd0) begin
                            parse_result <= ERR_DATA_LEN; //数据长度为0，错误
                            parse_done <= 1'b1;
                        end
                        else begin
                            data_len <= uart_rx_data;
                            skip_en <= 1'b1;
                            checksum <= checksum + uart_rx_data;
                        end
                    end
                end
                st_data: begin //接受数据并累加-----------------------------
                    if (uart_rx_done) begin
                        rec_data <= uart_rx_data;
                        rec_data_t <= rec_data; //这儿就只存了两个字节的数据,也就是16位，老的是_t
                        data_cnt <= data_cnt + 3'd1;
                        if (data_cnt < data_len) begin
                            data_cnt <= data_cnt + 3'd1; 
                            checksum <= uart_rx_data + checksum;
                        end
                        else
                            checksum <= checksum;
                        if (data_cnt == data_len - 8'd1) begin
                            data_cnt <= 3'd0;  //数据位最多8个字节，要加需要改所有data_cnt
                            skip_en <= 1'b1;
                        end
                    end
                end
                st_check:begin  //校验-------------------------------------
                if(uart_rx_done)begin
                    if(checksum == uart_rx_data)begin
                        skip_en      <= 1'b1;
                        parse_done   <= 1'b1;             //接收完成
                    end
                    else begin 
                        parse_result <= ERR_CHECKSUM;   //校验错误
                        parse_done    <= 1'b1;
                    end
                end
                end
                st_rx_end:begin //停止-------------------------------------
                    if(packet_tx_done)begin
                        skip_en       <= 1'b0 ;
                        parse_done    <= 1'b0 ;
                        parse_result  <= 8'b0 ;
                        parse_cmd     <= 8'd0 ;
                        checksum      <= 8'd0;
                        data_len      <= 8'd0 ;
                    end
                end
                default: ;
            endcase
        end
    end

    //接受完成后处理数据，启动不同的功能脉冲
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            fun0_en <= 1'b0;
            fun1_en <= 1'b0;
            fun2_en <= 1'b0;
            fun3_en <= 1'b0;
            fun4_en <= 1'b0;
            fun_parmeter <= 16'b0;
        end
        else begin
            if(parse_done)begin
                case(parse_cmd)
                    FUN0: begin
                        fun0_en <= 1'b1;
                        fun_parmeter <= {rec_data_t, rec_data};
                    end
                    FUN1: begin
                        fun1_en <= 1'b1;
                        fun_parmeter <= {rec_data_t, rec_data};
                    end
                    FUN2: begin
                        fun2_en <= 1'b1;
                        fun_parmeter <= {rec_data_t, rec_data};
                    end
                    FUN3: begin
                        fun3_en <= 1'b1;
                        fun_parmeter <= {rec_data_t, rec_data};
                    end
                    FUN4: begin
                        fun4_en <= 1'b1;
                        fun_parmeter <= {rec_data_t, rec_data};
                    end
                    default: ;
                endcase
            end
            else begin
                fun0_en <= 1'b0;
                fun1_en <= 1'b0;
                fun2_en <= 1'b0;
                fun3_en <= 1'b0;
                fun4_en <= 1'b0;
            end
        end
    end

endmodule